package com.zbb.online_exam.controller;
import com.zbb.online_exam.bean.JwtOperation;
import com.zbb.online_exam.constant.Method;
import com.zbb.online_exam.dto.JsonResult;
import com.zbb.online_exam.dto.UserDto;
import com.zbb.online_exam.entity.User;
import com.zbb.online_exam.exception.ExamException;
import com.zbb.online_exam.exception.ParamException;
import com.zbb.online_exam.service.UserService;
import com.zbb.online_exam.utils.HttpUtils;
import com.zbb.online_exam.vo.UpdateUserPwdVo;
import com.zbb.online_exam.vo.UserVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author zbbstart
 * @date 2021/2/8 - 15:29
 */
@RestController
@RequestMapping("users")
@Slf4j
@Api(tags = "用户操作相关的接口")
public class UserController {
    @Autowired
    private HttpUtils httpUtils;
    @Autowired
    private AuthenticationConfiguration authenticationConfiguration;
    @Autowired
    private JwtOperation jwtOperation;
    @Autowired
    private PasswordEncoder encoder;
    @Autowired
    @Qualifier("jdbcUseService")
    private UserDetailsService userDetailsService;
    @Autowired
    private UserService userService;

    /**
     * 登录
     *
     * @param userVo 前端创来的用户参数，其中
     *               getUsername    登录使用的用户名
     *               getPassword    登录使用的密码（注意：登录使用的是明文密码，数据库保存的是BCryptPasswordEncoder加密的密码）
     *               getUserRoleId  该用户的身份编号
     * @param res    响应对象
     * @return JSON格式的信息
     */
    @PostMapping("login")
    @ApiOperation(value = "登录", notes = "用户通过填写信息登录改系统")
    @ApiImplicitParam(paramType = "header", name = "userVo", dataType = "UserVo", required = true, value = "前端提交的用户信息")
    public JsonResult login(@RequestBody UserVo userVo, HttpServletResponse res) {
        JsonResult result = new JsonResult();
        try {
            //判断用户的各种情况
            userService.login(userVo);
            // 获取用户信息
            String name = userVo.getUsername();
            String pwd = userVo.getPassword();
            User userInfo = userService.getUserInfoByUserName(name);
            //获取认证管理器
            AuthenticationManager authenticationManager = authenticationConfiguration.getAuthenticationManager();
            Authentication authentication = authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(name, pwd));
            //存储认证信息
            SecurityContextHolder.getContext().setAuthentication(authentication);
            //获取认证通过的具体用户信息
            UserDetails userDetails = userDetailsService.loadUserByUsername(name);
            List<String> roles = userDetails.getAuthorities().stream().map(
                    e -> ((GrantedAuthority) e).getAuthority()).collect(Collectors.toList());
            //构建的用户对象
            UserDto user = new UserDto();
            user.setUserId(String.valueOf(userInfo.getId()));
            user.setUserName(userDetails.getUsername());
            user.setUserPwd(userDetails.getPassword());
            user.setRoles(roles);
            //创建JWT
            String token = jwtOperation.createJwt(user);
            result.setCode(200);
            //登录成功返回用户基本信息以及Token
            Map<String, Object> data = new LinkedHashMap<String, Object>();
            data.put("token", token);
            data.put("roles", roles);
            //首先让JWT存住密码，其次返回数据的时候置空密码，确保安全性
            user.setUserPwd(null);
            result.setData(data);
        } catch (ExamException ee) {
            ee.printStackTrace();
            result = httpUtils.buildFailure(ee.getMessage(), Method.GET);
        } catch (BadCredentialsException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
            result = httpUtils.build500();
        }
        //设置状态码
        res.setStatus(result.getCode());
        return result;
    }

    /**
     * 获取用户的信息
     */
    @GetMapping("/info")
    @ApiOperation(value = "获取用户信息", notes = "根据是否存在token获取用户信息")
    public JsonResult getLoginUserInfo(@ApiParam(name = "token", example = "") @RequestHeader("auth-token") String token, HttpServletResponse res) {
        JsonResult result = new JsonResult();
        try {
            UserDto user = userService.getUserInfoByToken(token);
            result = httpUtils.buildSuccess(Method.GET, user);
            res.setStatus(result.getCode());
        } catch (ParamException pe) {
            result = httpUtils.buildFailure(pe.getMessage(), Method.GET);
        } catch (Exception e) {
            e.printStackTrace();
            result = httpUtils.build500();
        }
        res.setStatus(result.getCode());
        return result;
    }

    /**
     * 修改密码
     */
    @PreAuthorize("hasAnyRole('ROLE_ADMIN','ROLE_TEACHER','ROLE_STUDENT')")
    @PostMapping("{userId}")
    @ApiOperation(value = "修改密码", notes = "根据用户编号，修改密码")
    public JsonResult updateUserPwd(@ApiParam(name = "userId", example = "1") @PathVariable("userId") Integer userId
            , @ApiParam(name = "userPwdVo", example = "") @RequestBody UpdateUserPwdVo userPwdVo, HttpServletResponse res) {
        JsonResult result = new JsonResult();
        try {
            userPwdVo.setUserId(userId);
            result = userService.updateUserPwd(userPwdVo);
        } catch (ExamException ee) {
            result = httpUtils.buildFailure(ee.getMessage(), Method.POST);
        } catch (Exception e) {
            e.printStackTrace();
            result = httpUtils.build500();
        }
        res.setStatus(result.getCode());
        return result;
    }

    /**
     * 更改用户的状态
     */
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    @PatchMapping("{userId}")
    @ApiOperation(value = "更改用户的状态", notes = "根据用户编号，更改用户的权限")
    public JsonResult updateUserStatus(@ApiParam(name = "userId", example = "9") @PathVariable("userId") Integer userId,
                                       HttpServletResponse res) {
        JsonResult result = new JsonResult();
        try {
            userService.updateUserStatus(userId);
        } catch (Exception e) {
            e.printStackTrace();
            result = httpUtils.build500();
        }
        res.setStatus(result.getCode());
        return result;

    }

}
